use crate::output::DigitalState;
use std::rc::Rc;

#[allow(unused)]
///All six provided structs implement Digital traits
pub trait Digital {
    fn get_output(&self) -> DigitalState;
}
#[allow(unused)]
#[macro_export]
///## EXAMPLE
///```rust
///
/// use std::rc::Rc;
/// use rust_play_digital::{generate_verify_digital_output_lines_trait, Digital, Digital1Line, DigitalState};
///    //This structure represents a semi-adder logic circuit
/// struct MyHalfAddElectric{
///    //input_a and input_b of the MyHalfAddElectric structure are defined as being one line circuit each.
///     input_a: Option<Rc<dyn Digital1Line>>,
///     input_b: Option<Rc<dyn Digital1Line>>,
///     input_a_states: DigitalState,
///     input_b_states: DigitalState,
///     output_states: DigitalState,
///     times: usize,
/// }
/// impl Digital for MyHalfAddElectric{fn get_output(&self) -> DigitalState {
///     self.output_states.clone()
///     }
/// }
///  //The Digital2Line trait checks whether the output lines of MyHalfAddElectric is two line circuits
///  //You can use the generated trait as a trait object type to constrain the input.
/// generate_verify_digital_output_lines_trait!(Digital2Line,2);
/// impl Digital2Line for MyHalfAddElectric{
/// }
///
/// ```
macro_rules! generate_verify_digital_output_lines_trait {
    ($trait_name:ident,$line_count:expr) => {

            pub trait $trait_name:Digital{
                fn get_digital_output(&self) -> DigitalState{
                    let ds = self.get_output();
                    if ds.lines() !=  $line_count {
                        panic!("{}",format!("digital output is {:?} expect {:?}",ds.lines(), $line_count ));
                    }
                    ds
                }
            }

    };
}
generate_verify_digital_output_lines_trait!(Digital1Line,1);
#[allow(unused)]
///AND OR XOR, these three structures implement TwoInputDigital trait
pub trait TwoInputDigital: Digital {
    ///Recalculate the circuit status when setting the input circuit
    fn set_input_a(&self, input_a: Option<Rc<dyn Digital1Line>>) -> Rc<Self>;
    ///Recalculate the circuit status when setting the input circuit
    fn set_input_b(&self, input_b: Option<Rc<dyn Digital1Line>>) -> Rc<Self>;
}

#[allow(unused)]
///NOT structures implement OneInputElectric trait
pub trait OneInputElectric: Digital {
    ///Recalculate the circuit status when setting the input circuit
    fn set_input(&self, input: Option<Rc<dyn Digital1Line>>) -> Rc<Self>;
}
